
import hashlib
import random
import string
import time
import requests
from xml.etree import ElementTree as ET
from django.conf import settings
from LogisticsCard.models import SystemConfig

class WXPay:
    def __init__(self):
        def get(key):
            obj = SystemConfig.objects.filter(key=key).first()
            return obj.value if obj else ''
        self.appid = get('appid')# 公众号
        self.mch_id = get('wx_sh_no')# 商户号
        self.api_key = get('wx_key')# 商户密钥
        site_host = settings.ALLOWED_HOSTS[1] if settings.ALLOWED_HOSTS and settings.ALLOWED_HOSTS[1] != '*' else '127.0.0.1'
        self.notify_url = f"http://{site_host}/wechatpay/notify/"
        self.unifiedorder_url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
        self.orderquery_url = "https://api.mch.weixin.qq.com/pay/orderquery"

    def generate_nonce_str(self, length=32):
        chars = string.ascii_letters + string.digits
        return ''.join(random.choice(chars) for _ in range(length))

    def create_sign(self, params):
        stringA = '&'.join([f"{k}={params[k]}" for k in sorted(params) if params[k]])
        stringSignTemp = f"{stringA}&key={self.api_key}"
        return hashlib.md5(stringSignTemp.encode('utf-8')).hexdigest().upper()

    def unified_order(self, body, out_trade_no, total_fee):
        spbill_create_ip = settings.ALLOWED_HOSTS[0] if settings.ALLOWED_HOSTS and settings.ALLOWED_HOSTS[0] != '*' else '127.0.0.1'
        params = {
            "appid": self.appid,
            "mch_id": self.mch_id,
            "nonce_str": self.generate_nonce_str(),
            "body": body,
            "out_trade_no": out_trade_no,
            "total_fee": str(total_fee),
            "spbill_create_ip": spbill_create_ip,
            "notify_url": self.notify_url,
            "trade_type": "NATIVE",
            "product_id": out_trade_no
        }
        sign = self.create_sign(params)
        params["sign"] = sign
        # 调试输出参数和签名
        print("[WXPay] unified_order参数:", params)
        print("[WXPay] 签名字符串:", sign)
        return self._post_xml(self.unifiedorder_url, params)

    def order_query(self, out_trade_no=None, transaction_id=None):
        params = {
            "appid": self.appid,
            "mch_id": self.mch_id,
            "nonce_str": self.generate_nonce_str()
        }
        if out_trade_no:
            params["out_trade_no"] = out_trade_no
        elif transaction_id:
            params["transaction_id"] = transaction_id
        else:
            raise ValueError("必须提供out_trade_no或transaction_id")
        
        params["sign"] = self.create_sign(params)
        return self._post_xml(self.orderquery_url, params)

    def _post_xml(self, url, params):
        xml_data = self._dict_to_xml(params)
        response = requests.post(url, data=xml_data.encode('utf-8'))
        return self._xml_to_dict(response.text)

    def _dict_to_xml(self, params):
        xml = ["<xml>"]
        for k, v in params.items():
            xml.append(f"<{k}>{v}</{k}>")
        xml.append("</xml>")
        return ''.join(xml)

    def _xml_to_dict(self, xml_data):
        # 尝试按utf-8解码，防止返回内容乱码
        if isinstance(xml_data, bytes):
            xml_data = xml_data.decode('utf-8', errors='replace')
        result = {}
        root = ET.fromstring(xml_data)
        for child in root:
            # 微信返回内容可能为GBK编码，尝试解码
            try:
                result[child.tag] = child.text.encode('raw_unicode_escape').decode('utf-8')
            except Exception:
                result[child.tag] = child.text
        return result

if __name__ == "__main__":
    # 配置参数（需替换为实际值）
    wxpay = WXPay()
    
    # Native支付示例
    print("=== Native支付演示 ===")
    native_result = wxpay.unified_order(
        body="测试商品",
        out_trade_no="NATIVE_" + str(int(time.time())),
        total_fee=100
    )
    print("支付结果:", native_result)
    if native_result.get("return_code") == "SUCCESS":
        print(f"二维码链接: {native_result.get('code_url')}")

    # 订单查询示例
    print("\n=== 订单查询演示 ===")
    query_result = wxpay.order_query(out_trade_no=native_result.get("out_trade_no"))
    print("查询结果:", query_result)
